/***********************
 * 负责代码的编译功能
************************/

#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>

#include "../comm/util.hpp"
#include "../comm/log.hpp"

namespace ns_compiler
{
	using namespace ns_util;
	using namespace ns_log;


	class Compiler
	{
	public:
	Compiler(){}
	~Compiler(){}
	public:
		//判断编译有没有错误
		//传入的文件名不带后缀，自己拼接
		//file_name: 1234
        //1234 -> ./temp/1234.cpp
        //1234 -> ./temp/1234.exeq
        //1234 -> ./temp/1234.stderr
		// 通过创建子进程让子进程进行进程替换g++编译
		static bool compile(const std::string& file_name)
		{
			pid_t id = fork();
			if(id < 0)
			{
				LOG(ERROR) << "内部错误，创建子进程失败" << "\n";
				return false;
			}
			else if(id == 0)
			{
				//子进程
				umask(0);
				//打开要编译文件
				int _stderr = open(PathUtil::CompileError(file_name).c_str(), O_CREAT | O_WRONLY, 0644);
				if(_stderr < 0)
				{
					LOG(WARNING) << "没有成功形成stderr文件" << "\n";
					exit(1);
				}

				//重定向标准错误到_stderr
				dup2(_stderr,2);

				//程序替换，并不影响进程的文件描述符表，会对页表进行自己拷贝一份
                //子进程: 调用编译器，完成对代码的编译工作
				execlp("g++","g++","-o",PathUtil::Exe(file_name).c_str(),PathUtil::Src(file_name).c_str(),"-D","COMPILER_ONLINE","-std=c++11",nullptr);
				LOG(ERROR) << "编译器g++启动失败，可能参数错误！" << "\n";
				exit(2);
			}
			else
			{
				// 父进程
				//对子进程进行等待
				waitpid(id,nullptr,0);
				//查看有没有可执行程序，有就编译成功，没有就出现错误
				if(FileUtil::IsFileExists(PathUtil::Exe(file_name)))
				{
					LOG(INFO) << PathUtil::Src(file_name) << "编译成功！" << "\n";
					return true;
				}
			}
			LOG(ERROR) << "编译失败，没有形成可执行程序" << "\n";
			return false;
		}
	};
}